package com.huffman.smart_picture.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huffman.smart_picture.common.UserSession;
import com.huffman.smart_picture.common.exception.ErrorEnum;
import com.huffman.smart_picture.domain.constants.CommonConstant;
import com.huffman.smart_picture.domain.constants.RedisConstant;
import com.huffman.smart_picture.domain.entity.FavoritePictureRecord;
import com.huffman.smart_picture.domain.entity.Picture;
import com.huffman.smart_picture.domain.enums.FavoriteEnum;
import com.huffman.smart_picture.domain.request.picture.PictureFavoriteRequest;
import com.huffman.smart_picture.mapper.FavoritePictureRecordMapper;
import com.huffman.smart_picture.service.FavoritePictureRecordService;
import com.huffman.smart_picture.service.PictureService;
import com.huffman.smart_picture.utils.ThrowUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * @author LinDeng
 * @description 针对表【favorite_picture_record(用户点赞记录表)】的数据库操作Service实现
 * @createDate 2025-05-06 16:08:50
 */
@Service("favoritePictureRecordService")
public class FavoritePictureRecordServiceImpl extends ServiceImpl<FavoritePictureRecordMapper, FavoritePictureRecord>
        implements FavoritePictureRecordService {
    private final TransactionTemplate transactionTemplate;
    private final PictureService pictureService;
    private final StringRedisTemplate redisTemplate;

    public FavoritePictureRecordServiceImpl(TransactionTemplate transactionTemplate, @Lazy PictureService pictureService, StringRedisTemplate redisTemplate) {
        this.transactionTemplate = transactionTemplate;
        this.pictureService = pictureService;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean doFavoritePicture(PictureFavoriteRequest pictureFavoriteRequest, UserSession userSession) {
        Long userId = userSession.getId();
        Long pictureId = pictureFavoriteRequest.getId();
        // 判断图片是否存在
        Picture picture = pictureService.getById(pictureId);
        ThrowUtil.throwIf(picture == null, ErrorEnum.RESOURCE_NOT_FIND, "图片不存在");

        boolean res;
        // 加锁点赞
        synchronized (userId.toString().intern()) {
            // 编程式事务
            res = Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                // 1.先查点赞记录表是否存在点赞记录
                FavoritePictureRecord record = getFavoritePictureRecord(userId, pictureId);
                boolean recordExist = haveFavoritePictureRecord(record);
                ThrowUtil.throwIf(recordExist, ErrorEnum.REQUEST_MANY, "请勿重复点赞");
                // 2.增加图片的点赞数
                boolean update = pictureService.lambdaUpdate()
                        .setSql("favorite_count = favorite_count +1")
                        .eq(Picture::getId, pictureId)
                        .update();
                // 3.插入点赞记录
                FavoritePictureRecord newRecord = new FavoritePictureRecord();
                if (record != null && record.getId() != null) {
                    newRecord.setId(record.getId());
                }
                newRecord.setUserId(userId);
                newRecord.setPictureId(pictureId);
                newRecord.setStatus(CommonConstant.EXIST);
                // 点赞数增加再插入记录
                boolean success = update && saveOrUpdate(newRecord);
                // 数据插入成功后写入redis
                if (success) {
                    insertFavoritePictureRecord(newRecord);
                }
                return success;
            }));
        }
        return res;
    }

    @Override
    public boolean undoFavoritePicture(PictureFavoriteRequest pictureFavoriteRequest, UserSession userSession) {
        Long userId = userSession.getId();
        Long pictureId = pictureFavoriteRequest.getId();
        // 判断图片是否存在
        boolean exists = pictureService.lambdaQuery()
                .eq(Picture::getId, pictureId)
                .exists();
        ThrowUtil.throwIf(!exists, ErrorEnum.RESOURCE_NOT_FIND, "图片不存在");

        boolean res;
        // 加锁点赞
        synchronized (userId.toString().intern()) {
            // 编程式事务
            res = Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                // 1.先查点赞记录表是否存在点赞记录
                FavoritePictureRecord record = getFavoritePictureRecord(userId, pictureId);
                boolean recordNotExist = !haveFavoritePictureRecord(record);
                ThrowUtil.throwIf(recordNotExist, ErrorEnum.REQUEST_MANY, "请勿重复取消点赞");

                // 2.减少图片的点赞数
                boolean update = pictureService.lambdaUpdate()
                        .setSql("favorite_count = favorite_count -1")
                        .eq(Picture::getId, pictureId)
                        .update();
                // 3.插入点赞记录（将status状态改为取消状态）
                FavoritePictureRecord newRecord = new FavoritePictureRecord();
                newRecord.setId(record.getId());
                newRecord.setUserId(userId);
                newRecord.setPictureId(pictureId);
                newRecord.setStatus(CommonConstant.NOT_EXIST);
                // 点赞数减少再插入记录
                boolean success = update && saveOrUpdate(newRecord);
                // 删除缓存中的点赞记录
                if (success) {
                    deleteFavoritePictureRecord(record);
                }
                return success;
            }));
        }
        return res;
    }

    /**
     * 判断是否有点赞记录
     *
     * @param userId
     * @param pictureId
     * @return
     */
    @Override
    public boolean haveFavoritePictureRecord(Long userId, Long pictureId) {
        FavoritePictureRecord record = null;
        // 先查缓存 缓存中判断是否点赞
        String key = RedisConstant.FAVORITE_PICTURE_RECORD + ":" + userId;
        record = (FavoritePictureRecord) redisTemplate.opsForHash().get(key, pictureId.toString());
        if (haveFavoritePictureRecord(record)) {
            return true;
        }
        // 缓存中没有 查数据库
        record = getFavoritePictureRecord(userId, pictureId);
        return haveFavoritePictureRecord(record);
    }

    /**
     * 根据记录对象进行判断是否点赞
     *
     * @param favoritePictureRecord
     * @return
     */
    private boolean haveFavoritePictureRecord(FavoritePictureRecord favoritePictureRecord) {
        return favoritePictureRecord != null && FavoriteEnum.DO.getStatus().equals(favoritePictureRecord.getStatus());
    }

    /**
     * 获取用户点赞记录
     *
     * @param userId
     * @param pictureId
     * @return
     */
    private FavoritePictureRecord getFavoritePictureRecord(Long userId, Long pictureId) {
        return this.getBaseMapper().getRecordByUserIdAndPicId(userId, pictureId);
    }

    /**
     * 插入用户点赞记录id到redis中
     *
     * @param favoritePictureRecord
     */
    private void insertFavoritePictureRecord(FavoritePictureRecord favoritePictureRecord) {
        Long userId = favoritePictureRecord.getUserId();
        Long pictureId = favoritePictureRecord.getPictureId();
        String key = RedisConstant.FAVORITE_PICTURE_RECORD + ":" + userId;
        redisTemplate.opsForHash().put(key, pictureId, favoritePictureRecord);
    }

    /**
     * 删除redis中用户点赞记录
     *
     * @param favoritePictureRecord
     */
    private void deleteFavoritePictureRecord(FavoritePictureRecord favoritePictureRecord) {
        Long userId = favoritePictureRecord.getUserId();
        Long pictureId = favoritePictureRecord.getPictureId();
        String key = RedisConstant.FAVORITE_PICTURE_RECORD + ":" + userId;
        redisTemplate.opsForHash().delete(key, pictureId);
    }
}




